﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace hlavny
{
    [Serializable]
    class cIndHashFile
    {
        /// <summary>
        ///  Dlzka hlavicky bloku
        /// </summary>

        const int HEADER_LENGTH = 17;

        /// <summary>
        /// Dlzka samotneho kluca
        /// </summary>
        private int piKeyLength;

        /// <summary>
        /// Dlzka zaznamu
        /// </summary>
        private int piRecordLength;

        /// <summary>
        /// Dlzka halvicky
        /// </summary>
        private int piHeaderLength;

        /// <summary>
        /// Pocet zaznamov v jednom buckete
        /// </summary>
        private int piNumberOfRecordsInBucket;

        /// <summary>
        /// Subor na manipulaciu
        /// </summary>
        private cIndFileManipulation poFile;

        /// <summary>
        /// piItems
        /// </summary>
        private int piUsedBits;

        /// <summary>
        /// Adresar
        /// </summary>
        [NonSerialized]
        private List<long> piItems = new List<long>();

        /// <summary>
        /// Obmedzenie velkosti adresara v KB
        /// </summary>
        private long piArrayLength = 1024;

        public long iArrayLength
        {
            get { return piArrayLength / 1024; }
            set { piArrayLength = value * 1024; }
        }

        /// <summary>
        /// Aktualna dlzka adresara
        /// </summary>
        private int piArrayCount;

        /// <summary>
        /// Nazov suboru, kde je ulozeny adresar
        /// </summary>
        private string psAddressFileName;

        public string sAddressFileName
        {
            get { return psAddressFileName; }
            set { psAddressFileName = value; }
        }

        /// <summary>
        /// Hashovacia funkcia, ktora sa pouziva
        /// </summary>
        private int piUsedHash;

        // Posledna pozicia z pola, ktora bola nacitana
        private int piLastArrayPositon;

        // Pomer, po dosiahnuti ktoreho sa ma reorganizovat pole smernikov = 
        // = pomer pocet vymazanych / velkost bucketu
        private int piNumberOfDeleted;


        /// <summary>
        /// Typ kluca v tvare "hlavny.modul1.typ"
        /// </summary>
        private string psKeyObjName;

        public string sKeyObjName
        {
            get { return psKeyObjName; }
            set { psKeyObjName = value; }
        }

        /// <summary>
        /// Dlzka kluca
        /// </summary>
        private int piKeyObjLength;

        public int iKeyObjLength
        {
            get { return piKeyObjLength; }
            set { piKeyObjLength = value; }
        }

        
        private int piDeleteReorganizeRatio = 1;

        // Pre vyhladavanie dalsieho kluca
        /// <summary>
        /// Posledny vyhladavany kluc
        /// </summary>
        private byte[] paLastKey = null;

        /// <summary>
        /// Kolkata hodnota bola najdena
        /// </summary>
        private int piFoundCount = 0;
        /// <summary>
        /// Posledna adresa, na ktorej bol najdeny kluc
        /// </summary>
        private long piLastAddressForSearch;

        // Statistiky
        /// <summary>
        /// Ci sa pouzivaju okamzite statistiky alebo analyze
        /// </summary>
        private bool pbUseImmediateStats = false;
        public bool bUseImmediateStats
        {
            get { return pbUseImmediateStats; }
            set { pbUseImmediateStats = value; }
        }
        /// <summary>
        /// Pocet hlavnych blokov
        /// </summary>
        private int piMainBlocks;
        /// <summary>
        /// Pocet zaznamov v hlavnych blokoch
        /// </summary>
        private long piRecordsInMainBlocks;
        /// <summary>
        /// Pocet preplnovacich blokov
        /// </summary>
        private int piOverloadBlocks;
        /// <summary>
        /// Pocet zaznamov v prelnovacich blokoch
        /// </summary>
        private long piRecordsInOverloadBlocks;

        /// <summary>
        /// Minimalna hodnota kluca
        /// </summary>
        private modul1.Object poMinValue = null;

        public modul1.Object oMinValue
        {
            get { return poMinValue; }
            set { poMinValue = value; }
        }

        /// <summary>
        /// Maximalna hodnota kluca
        /// </summary>
        private modul1.Object poMaxValue = null;

        public modul1.Object oMaxValue
        {
            get { return poMaxValue; }
            set { poMaxValue = value; }
        }

        /// <summary>
        /// Zoznam 10 najvacsich hodnot
        /// </summary>
        private List<modul1.Object> paMaxValues = new List<hlavny.modul1.Object>();
        /// <summary>
        /// Zoznam 10 najmensich hodnot
        /// </summary>
        private List<modul1.Object> paMinValues = new List<hlavny.modul1.Object>();
        /// <summary>
        /// Ci uz boli zoznamy hodnot inicializovane na max velkost alebo nie
        /// </summary>
        private bool pbFilled = false;

        /// <summary>
        /// Pocet roznych hodnot
        /// </summary>
         private int piDifValues = 0;

        public int iDifValues
        {
            get { return piDifValues; }
            set { piDifValues = value; }
        }

        /// <summary>
        /// Vyuzitie hlavnych blokov
        /// </summary>
        public float iMainBlocksUsage
        {
            get
            {
                if (piMainBlocks > 0)
                {
                    return (float)piRecordsInMainBlocks / ((float)piMainBlocks * (float)piNumberOfRecordsInBucket);
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// Vyuzitie preplnovacich blokov
        /// </summary>
        public float iOverloadBlocksUsage
        {
            get
            {
                if (piOverloadBlocks > 0)
                {
                    return (float)piRecordsInOverloadBlocks / ((float)piOverloadBlocks * (float)piNumberOfRecordsInBucket);
                }
                else
                {
                    return 0;
                }
            }
        }

        /// <summary>
        /// Pomer pocet vymazanych/pocet zaznamov v bloku, kedy treba reorganizovat subory
        /// </summary>
        public int iDeleteReorganizeRatio
        {
            get { return piDeleteReorganizeRatio; }
            set { piDeleteReorganizeRatio = value; }
        }
        /// <summary>
        /// Nazov suboru
        /// </summary>
        public string sFileName
        {
            get { return poFile.sFileName; }
        }

        /// <summary>
        /// Inicializovanie premennych kvoli deserializacii
        /// </summary>
        public void reloadFile()
        {
            piItems = new List<long>();
        }
        /// <summary>
        /// Vytvori index
        /// </summary>
        /// <param name="pa_sFileName">Nazov suboru</param>
        /// <param name="pa_iKeyLength">Dlzka kluca v poli bytoch</param>
        /// <param name="pa_iNumberOfRecordsInBucket">Pocet zaznamov v buckete</param>
        /// <param name="pa_sKeyObjName">Nazov objektu kluca</param>
        /// <param name="pa_iKeyObjLength">Dlzka kluca - dolezite len pri charactere</param>
        /// <param name="pa_iHashFunction">Pouzita hashovacia funkcia</param>
        public cIndHashFile(string pa_sFileName, int pa_iKeyLength, int pa_iNumberOfRecordsInBucket, string pa_sKeyObjName, int pa_iKeyObjLength, int pa_iHashFunction)
        {
            piUsedHash = pa_iHashFunction;
            psAddressFileName = pa_sFileName + "_add.dat";
            piUsedBits = 1;
            piKeyLength = pa_iKeyLength;
            piNumberOfRecordsInBucket = pa_iNumberOfRecordsInBucket;
            piRecordLength = sizeof(long) + pa_iKeyLength;
            poFile = new cIndFileManipulation(pa_sFileName, pa_iNumberOfRecordsInBucket, piRecordLength, piKeyLength);
            piHeaderLength = poFile.iLengthOfHeader;
            psKeyObjName = pa_sKeyObjName;
            piKeyObjLength = pa_iKeyObjLength;
            pbUseImmediateStats = true;
            piMainBlocks = 2;
            piOverloadBlocks = 0;
            piRecordsInMainBlocks = 0;
            piRecordsInOverloadBlocks = 0;
            FileStream rFile = null;

            if (!File.Exists(psAddressFileName))
            {
                try
                {
                    rFile = System.IO.File.Create(psAddressFileName);
                }
                catch (Exception)
                {
                    throw (new Exception("Problem pri vytvarani suboru"));
                }
                finally
                {
                    rFile.Close();
                }
            }
            if (File.Exists(psAddressFileName))
            {
                try
                {
                    rFile = File.Open(psAddressFileName, FileMode.Open);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    rFile.Close();
                    throw ex;
                }
            }
            else
            {
                throw (new Exception("Subor sa nepodarilo otvorit"));
            }

            rFile.Seek(0, SeekOrigin.Begin);
            BinaryWriter rWriter = new BinaryWriter(rFile);
            piItems.Add(poFile.createNewBlock());
            piItems.Add(poFile.createNewBlock());
            piArrayCount = 2;
            piLastArrayPositon = 0;
            rWriter.Write(piItems[0]);
            rWriter.Write(piItems[1]);
            rFile.Close();
        }

        /// <summary>
        /// Vrati danu adresu v adresari a ak je treba, tak nacita zo suboru novu
        /// </summary>
        /// <param name="pa_iPosition"></param>
        /// <returns></returns>
        private long getAddress(int pa_iPosition)
        {
            FileStream rFile = null;
            if (pa_iPosition >= piLastArrayPositon && pa_iPosition < piLastArrayPositon + piArrayLength / 8 && pa_iPosition - piLastArrayPositon < piItems.Count)
            {
                return piItems[pa_iPosition - piLastArrayPositon];
            }
            else
            {
                if (File.Exists(psAddressFileName) == true)
                {
                    try
                    {
                        rFile = File.Open(psAddressFileName, FileMode.Open);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        rFile.Close();
                        throw ex;
                    }
                }
                else
                {
                    throw (new Exception("Subor sa nepodarilo otvorit"));
                }
                piItems.Clear();
                rFile.Seek(pa_iPosition * 8, SeekOrigin.Begin);
                BinaryReader rReader = new BinaryReader(rFile);
                piLastArrayPositon = pa_iPosition;
                for (int ii = pa_iPosition; ii < pa_iPosition + piArrayLength / 8 && ii < piArrayCount; ii++)
                {
                    piItems.Add(rReader.ReadInt64());
                }
                rFile.Close();
                return piItems[0];
            }
        }

        /// <summary>
        /// Zmeni casti pola na zadane
        /// </summary>
        /// <param name="pa_iStartPosition"></param>
        /// <param name="pa_iLength"></param>
        /// <param name="pa_iAddress"></param>
        private void setArray(int pa_iStartPosition, int pa_iLength, long pa_iAddress)
        {
            FileStream rFile = null;

            if (File.Exists(psAddressFileName))
            {
                try
                {
                    rFile = File.Open(psAddressFileName, FileMode.Open);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    rFile.Close();
                    throw ex;
                }
            }
            else
            {
                throw (new Exception("Subor sa nepodarilo otvorit"));
            }

            rFile.Seek(pa_iStartPosition * 8, SeekOrigin.Begin);
            BinaryWriter rWriter = new BinaryWriter(rFile);
            for (int ii = 0; ii < pa_iLength; ii++)
            {
                rWriter.Write(pa_iAddress);
            }
            rFile.Close();
            int iEndLoad = piLastArrayPositon + (int)(piArrayLength / 8) - 1;
            int iEndSave = pa_iStartPosition + pa_iLength - 1;
            // Treba menit nacitane pole
            if ((piLastArrayPositon >= pa_iStartPosition && iEndLoad >= iEndSave && iEndSave >= piLastArrayPositon)
            || (piLastArrayPositon <= pa_iStartPosition && iEndLoad <= iEndSave && pa_iStartPosition <= iEndLoad)
            || (piLastArrayPositon <= pa_iStartPosition && iEndLoad >= iEndSave)
            || (piLastArrayPositon >= pa_iStartPosition && iEndLoad <= iEndSave))
            {
                for (int ii = piLastArrayPositon < pa_iStartPosition ? pa_iStartPosition : piLastArrayPositon; ii < iEndSave + 1 && ii < iEndLoad + 1 && ii - piLastArrayPositon < piItems.Count; ii++)
                {
                    piItems[ii - piLastArrayPositon] = pa_iAddress;
                }
            }
            else
            {
                getAddress(pa_iStartPosition);
            }

        }

        /// <summary>
        /// Porovna 2 polia bytov, ci sa rovnaju
        /// </summary>
        /// <param name="pa_aArr1"></param>
        /// <param name="pa_aArr2"></param>
        /// <returns></returns>
        private bool compareByte(byte[] pa_aArr1, byte[] pa_aArr2)
        {
            bool bReturn = true;
            for (int ii = 0; ii < pa_aArr1.Length; ii++)
            {
                if (pa_aArr1[ii] != pa_aArr2[ii])
                {
                    bReturn = false;
                }
            }
            return bReturn;
        }

        /// <summary>
        /// Reorganizuje pole
        /// </summary>
        /// <param name="pa_iNewDepth"></param>
        private void reorganizeArray(int pa_iNewDepth)
        {
            if (pa_iNewDepth > piUsedBits)
            {
                FileStream rFile = null;
                try
                {
                    rFile = System.IO.File.Create(psAddressFileName + ".new");
                }
                catch (Exception)
                {
                    throw (new Exception("Problem pri vytvarani suboru"));
                }
                finally
                {
                    rFile.Close();
                }
                if (File.Exists(psAddressFileName + ".new"))
                {
                    try
                    {
                        rFile = File.Open(psAddressFileName + ".new", FileMode.Open);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        rFile.Close();
                        throw ex;
                    }
                }
                else
                {
                    throw (new Exception("Subor sa nepodarilo otvorit"));
                }

                BinaryWriter rWriter = new BinaryWriter(rFile);

                // prepise adresy v subore
                if (piLastArrayPositon == 0 && piArrayCount <= piArrayLength / 8)
                {
                    rFile.Seek(0, SeekOrigin.End);
                    for (int ii = 0; ii < piItems.Count; ii++)
                    {
                        rWriter.Write((long)piItems[ii]);
                        rWriter.Write((long)piItems[ii]);
                    }
                }
                else
                {
                    FileStream rNewFile = null;
                    if (File.Exists(psAddressFileName))
                    {
                        try
                        {
                            rNewFile = File.Open(psAddressFileName, FileMode.Open);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                            rNewFile.Close();
                            throw ex;
                        }
                    }
                    else
                    {
                        throw (new Exception("Subor sa nepodarilo otvorit"));
                    }
                    BinaryReader rReader = new BinaryReader(rNewFile);
                    rNewFile.Seek(0, SeekOrigin.Begin);
                    piItems.Clear();
                    long iAdd;
                    for (int ii = 0; ii < piArrayCount; ii++)
                    {
                        iAdd = rReader.ReadInt64();
                        //rFile.Seek(0, SeekOrigin.End);
                        rWriter.Write(iAdd);
                        rWriter.Write(iAdd);
                    }

                    rNewFile.Close();
                }
                Console.WriteLine(piItems.Count);

                rFile.Close();
                piArrayCount *= 2;
                System.IO.File.Delete(psAddressFileName);
                System.IO.File.Move(psAddressFileName + ".new", psAddressFileName);


                //Upravi nacitane
                if (piLastArrayPositon == 0 && piArrayLength / 8 >= piArrayCount)
                {
                    for (int ii = 0; ii < piArrayCount / 2; ii++)
                    {
                        piItems.Add(0);
                    }
                    for (int ii = (int)(piArrayCount / 2) - 1; ii >= 0; ii--)
                    {
                        piItems[ii * 2] = piItems[ii];
                        piItems[ii * 2 + 1] = piItems[ii];
                    }
                }
                else
                {
                    piItems.Clear();
                }
            }
            else
            {
                FileStream rFile = null;
                if (!File.Exists(psAddressFileName))
                {
                    try
                    {
                        rFile = System.IO.File.Create(psAddressFileName + ".new");
                    }
                    catch (Exception)
                    {
                        throw (new Exception("Problem pri vytvarani suboru"));
                    }
                }
                if (File.Exists(psAddressFileName + ".new"))
                {
                    try
                    {
                        rFile = File.Open(psAddressFileName + ".new", FileMode.Open);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        rFile.Close();
                        throw ex;
                    }
                }
                else
                {
                    throw (new Exception("Subor sa nepodarilo otvorit"));
                }
                // Prepise adresy v subore
                BinaryWriter rWriter = new BinaryWriter(rFile);
                int iCount = 0;
                while (iCount < piArrayCount)
                {
                    if (iCount == piLastArrayPositon)
                    {
                        FileStream rNewFile = null;
                        if (File.Exists(psAddressFileName))
                        {
                            try
                            {
                                rNewFile = File.Open(psAddressFileName, FileMode.Open);
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex.Message);
                                rNewFile.Close();
                                throw ex;
                            }
                        }
                        else
                        {
                            throw (new Exception("Subor sa nepodarilo otvorit"));
                        }
                        BinaryReader rReader = new BinaryReader(rNewFile);
                        rNewFile.Seek(iCount, SeekOrigin.Begin);
                        piItems.Clear();
                        for (int ii = 0; ii < piArrayLength / 8 && ii + iCount < piArrayCount; ii++)
                        {
                            piItems.Add(rReader.ReadInt64());
                        }
                        piLastArrayPositon = iCount;
                        rNewFile.Close();
                    }
                    getAddress(iCount);
                    for (int ii = 0; ii < piItems.Count; ii += 2)
                    {
                        rWriter.Write(piItems[ii]);
                    }
                    iCount += (int)(piArrayLength / 8);
                }
                rFile.Close();
                piArrayCount /= 2;
                System.IO.File.Delete(psAddressFileName);
                System.IO.File.Move(psAddressFileName + ".new", psAddressFileName);

                // zmeni nacitane adresy
                if (piLastArrayPositon == 0 && piArrayLength / 8 >= piArrayCount)
                {
                    for (int ii = 0; ii < piArrayCount; ii++)
                    {
                        piItems[ii] = piItems[ii * 2];
                    }
                    piItems.RemoveRange((int)piArrayCount, (int)piArrayCount);
                }
                else
                {
                    for (int ii = 0; ii < piItems.Count / 2; ii++)
                    {
                        piItems[ii] = piItems[ii * 2];
                    }
                    piItems.RemoveRange(piItems.Count / 2, piItems.Count / 2);
                }
            }
            piUsedBits = pa_iNewDepth;
        }

        /// <summary>
        /// Vlozi novu hodnotu
        /// </summary>
        /// <param name="pa_aKey">Kluc</param>
        /// <param name="pa_iRowid">Rowid</param>
        public void insertValue(byte[] pa_aKey, long pa_iRowid)
        {
            uint hash = getHash(pa_aKey);
            string binar = convertToBinary(hash);
            int iArrayPosition = convertFromBinary(binar.Substring(0, piUsedBits));
            long oldAdresa = getAddress(iArrayPosition);
            // Nacita blok kam patri zaznam
            cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oldAdresa, poFile.readBlock(oldAdresa), psKeyObjName, piKeyObjLength);

            // Ci je este miesto
            if (oTempBlock.iNumberOfRecords == piNumberOfRecordsInBucket)
            {
                // Ak sa pouziva vsetkych 32 bitov, tak uz nemozeme rozsirovat adresar dalej, ale pridame preplnovaci blok
                if (piUsedBits < 32)
                {
                    List<cIndBlock> aBlocks = new List<cIndBlock>();
                    aBlocks.Add(oTempBlock);
                    if (oTempBlock.iChain != -1)
                    {
                        long iChain = oTempBlock.iChain;
                        while (iChain != -1)
                        {
                            oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iChain, poFile.readBlock(iChain), psKeyObjName, piKeyObjLength);
                            iChain = oTempBlock.iChain;
                            aBlocks.Add(oTempBlock);
                        }
                    }
                    // Spocita kolko hodnot hash funkcie je v danom bloku
                    Dictionary<string, int> aKeyHashValues = new Dictionary<string, int>();
                    for (int ii = 0; ii < aBlocks.Count; ii++)
                    {
                        for (int jj = 0; jj < aBlocks[ii].iNumberOfRecords; jj++)
                        {
                            string sHashValue = convertToBinary(getHash(aBlocks[ii][jj].aKey));
                            if (aKeyHashValues.ContainsKey(sHashValue) == true)
                            {
                                aKeyHashValues[sHashValue] = aKeyHashValues[sHashValue] + 1;
                            }
                            else
                            {
                                aKeyHashValues.Add(sHashValue, 1);
                            }
                        }
                    }
                    // Prida aj vkladanu hodnotu 
                    string sHashVal = convertToBinary(getHash(pa_aKey));
                    if (aKeyHashValues.ContainsKey(sHashVal) == true)
                    {
                        aKeyHashValues[sHashVal] = aKeyHashValues[sHashVal] + 1;
                    }
                    else
                    {
                        aKeyHashValues.Add(sHashVal, 1);
                    }

                    if (aKeyHashValues.Count == 1)
                    {
                        //Bucket obsahuje hodnoty len s 1 hash funkciou a treba pridat preplnovaci blok alebo doplnit existujuci
                        if (aBlocks[aBlocks.Count - 1].iNumberOfRecords < piNumberOfRecordsInBucket)
                        {
                            aBlocks[aBlocks.Count - 1].addRecord(pa_aKey, pa_iRowid);
                            poFile.writeBlock(aBlocks[aBlocks.Count - 1].iAddress, aBlocks[aBlocks.Count - 1].toByteArray());
                            if (pbUseImmediateStats == true)
                            {
                                if (aBlocks.Count > 1)
                                {
                                    piRecordsInMainBlocks++;
                                }
                                else
                                {
                                    piRecordsInOverloadBlocks++;
                                }
                            }
                        }
                        else
                        {
                            // Bucket obsahuje viac hodnot
                            long iNewAddress = poFile.createNewBlock();
                            cIndBlock oNewBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iNewAddress, psKeyObjName, piKeyObjLength);
                            oNewBlock.addRecord(pa_aKey, pa_iRowid);
                            poFile.writeBlock(oNewBlock.iAddress, oNewBlock.toByteArray());
                            aBlocks[aBlocks.Count - 1].iChain = oNewBlock.iAddress;
                            poFile.writeBlock(aBlocks[aBlocks.Count - 1].iAddress, aBlocks[aBlocks.Count - 1].toByteArray());
                            if (pbUseImmediateStats == true)
                            {
                                piRecordsInOverloadBlocks++;
                                piOverloadBlocks++;
                            }
                        }
                    }
                    else
                    {
                        int iDepth = aBlocks[0].iDepth;
                        //Netreba reorganizovat pole
                        if (iDepth < piUsedBits)
                        {
                            // Najdenie casti adresara, ktora sa ma delit, najde aj deliacu hodnotu, podla ktorej sa budu delit hodnoty
                            string sBinar = convertToBinary(getHash(pa_aKey));
                            int iFirstPosition = (int)convertFromBinary(((sBinar).Substring(0, iDepth)).PadRight(piUsedBits, '0'));
                            if (iFirstPosition == 1)
                            {
                                iFirstPosition = 0;
                            }
                            int iNumberOfSlots = (int)Math.Pow(2, piUsedBits - iDepth);
                            int iUpperHalf = iFirstPosition + iNumberOfSlots / 2;

                            string sBin = convertToBinaryNo(iUpperHalf);
                            sBin = sBin.PadLeft(piUsedBits, '0');
                            if (sBin.Length < iDepth + 1)
                            {
                                sBin = sBin.PadLeft(iDepth + 1, '0');
                            }
                            int iUpperNo = convertFromBinary((sBin.Substring(0, iDepth + 1)));

                            List<cIndRecord> oFirstHalf = new List<cIndRecord>();
                            List<cIndRecord> oSecondHalf = new List<cIndRecord>();
                            // Rozdelenie na 2 casti podla hodnoty hash funkcie
                            for (int ii = 0; ii < aBlocks.Count; ii++)
                            {
                                for (int jj = 0; jj < aBlocks[ii].iNumberOfRecords; jj++)
                                {
                                    string sBinRepr = convertToBinary(getHash(aBlocks[ii][jj].aKey));
                                    if (string.Compare(sBinRepr.Substring(0, iDepth + 1), sBin.Substring(0, iDepth + 1)) >= 0)
                                    {
                                        oSecondHalf.Add(aBlocks[ii][jj]);
                                    }
                                    else
                                    {
                                        oFirstHalf.Add(aBlocks[ii][jj]);
                                    }
                                }
                            }

                            if (pbUseImmediateStats == true)
                            {
                                for (int ii = 0; ii < aBlocks.Count; ii++)
                                {
                                    if (ii == 0)
                                    {
                                        piRecordsInMainBlocks -= aBlocks[0].iNumberOfRecords;
                                        piMainBlocks--;
                                    }
                                    else
                                    {
                                        piRecordsInOverloadBlocks -= aBlocks[ii].iNumberOfRecords;
                                        piOverloadBlocks--;
                                    }
                                }
                            }

                            // Vlozenie prvej casti, aj so zretazenymi blokmi, ak su
                            long iPosition = oldAdresa;
                            // Ktory index z pola zretazenych blokov sa pouziva
                            int iUsedIndex = 0;

                            if (oFirstHalf.Count > piNumberOfRecordsInBucket)
                            {
                                while (oFirstHalf.Count != 0)
                                {
                                    int iRecordsToMoveCount = 0;
                                    if (oFirstHalf.Count < piNumberOfRecordsInBucket)
                                    {
                                        iRecordsToMoveCount = oFirstHalf.Count;
                                    }
                                    else
                                    {
                                        iRecordsToMoveCount = piNumberOfRecordsInBucket;
                                    }

                                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, aBlocks[iUsedIndex].iAddress, psKeyObjName, piKeyObjLength);
                                    for (int ii = oFirstHalf.Count - iRecordsToMoveCount; ii < oFirstHalf.Count; ii++)
                                    {
                                        oTempBlock.addRecord(oFirstHalf[ii].aKey, oFirstHalf[ii].iRowid);
                                    }

                                    oFirstHalf.RemoveRange(oFirstHalf.Count - iRecordsToMoveCount, iRecordsToMoveCount);
                                    if (oFirstHalf.Count != 0)
                                    {
                                        oTempBlock.iChain = aBlocks[iUsedIndex + 1].iAddress;
                                    }
                                    oTempBlock.iDepth = iDepth + 1;

                                    poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                                    if (pbUseImmediateStats == true)
                                    {
                                        if (iUsedIndex == 0)
                                        {
                                            piRecordsInMainBlocks += oTempBlock.iNumberOfRecords;
                                            piMainBlocks++;
                                        }
                                        else
                                        {
                                            piRecordsInOverloadBlocks += oTempBlock.iNumberOfRecords;
                                            piOverloadBlocks++;
                                        }
                                    }
                                    iUsedIndex++;

                                }
                            }
                            else
                            {
                                // Je len jeden blok
                                oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, aBlocks[iUsedIndex].iAddress, psKeyObjName, piKeyObjLength);
                                for (int ii = 0; ii < oFirstHalf.Count; ii++)
                                {
                                    oTempBlock.addRecord(oFirstHalf[ii].aKey, oFirstHalf[ii].iRowid);
                                }
                                oTempBlock.iDepth = iDepth + 1;
                                if (pbUseImmediateStats == true)
                                {
                                    if (iUsedIndex == 0)
                                    {
                                        piRecordsInMainBlocks += oTempBlock.iNumberOfRecords;
                                        piMainBlocks++;
                                    }
                                }
                                poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                                iUsedIndex++;
                            }
                            // Vlozenie druhej polovice
                            long iNewAddress = -1;
                            bool iFirst = true;
                            if (oSecondHalf.Count > piNumberOfRecordsInBucket)
                            {
                                long iChainAddres = -1;
                                while (oSecondHalf.Count != 0)
                                {
                                    long iLastAddress;
                                    int iRecordsToMoveCount = 0;
                                    if (oSecondHalf.Count < piNumberOfRecordsInBucket)
                                    {
                                        iRecordsToMoveCount = oSecondHalf.Count;
                                    }
                                    else
                                    {
                                        iRecordsToMoveCount = piNumberOfRecordsInBucket;
                                    }

                                    if (iUsedIndex < aBlocks.Count)
                                    {
                                        iLastAddress = aBlocks[iUsedIndex].iAddress;
                                    }
                                    else
                                    {
                                        if (iChainAddres != -1)
                                        {
                                            iLastAddress = iChainAddres;
                                        }
                                        else
                                        {
                                            iLastAddress = poFile.createNewBlock();
                                        }
                                    }
                                    if (iNewAddress == -1)
                                    {
                                        iNewAddress = iLastAddress;
                                    }
                                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iLastAddress, psKeyObjName, piKeyObjLength);
                                    for (int ii = oSecondHalf.Count - iRecordsToMoveCount; ii < oSecondHalf.Count; ii++)
                                    {
                                        oTempBlock.addRecord(oSecondHalf[ii].aKey, oSecondHalf[ii].iRowid);
                                    }

                                    oSecondHalf.RemoveRange(oSecondHalf.Count - iRecordsToMoveCount, iRecordsToMoveCount);
                                    if (oSecondHalf.Count != 0)
                                    {
                                        if (iUsedIndex + 1 < aBlocks.Count)
                                        {
                                            oTempBlock.iChain = aBlocks[iUsedIndex + 1].iAddress;
                                        }
                                        else
                                        {
                                            iChainAddres = poFile.createNewBlock();
                                            oTempBlock.iChain = iChainAddres;
                                        }
                                    }
                                    oTempBlock.iDepth = iDepth + 1;
                                    if (pbUseImmediateStats == true)
                                    {
                                        if (iFirst == true)
                                        {
                                            iFirst = false;
                                            piRecordsInMainBlocks += oTempBlock.iNumberOfRecords;
                                            piMainBlocks++;
                                        }
                                        else
                                        {
                                            piOverloadBlocks++;
                                            piRecordsInOverloadBlocks += oTempBlock.iNumberOfRecords;
                                        }
                                    }
                                    poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                                    iUsedIndex++;
                                }
                            }
                            else
                            {
                                if (iUsedIndex < aBlocks.Count)
                                {
                                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, aBlocks[iUsedIndex].iAddress, psKeyObjName, piKeyObjLength);
                                }
                                else
                                {
                                    long iAddress = poFile.createNewBlock();
                                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iAddress, psKeyObjName, piKeyObjLength);
                                }
                                if (iNewAddress == -1)
                                {
                                    iNewAddress = oTempBlock.iAddress;
                                }
                                for (int ii = 0; ii < oSecondHalf.Count; ii++)
                                {
                                    oTempBlock.addRecord(oSecondHalf[ii].aKey, oSecondHalf[ii].iRowid);
                                }
                                oTempBlock.iDepth = iDepth + 1;
                                if (pbUseImmediateStats == true)
                                {
                                    piRecordsInMainBlocks += oTempBlock.iNumberOfRecords;
                                    piMainBlocks++;
                                }
                                poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                                iUsedIndex++;
                            }

                            // Prepisanie pola s adresami
                            setArray(iUpperHalf, iNumberOfSlots / 2, iNewAddress);
                            if (iUsedIndex < aBlocks.Count)
                            {
                                for (int ii = iUsedIndex; ii < aBlocks.Count; ii++)
                                {
                                    poFile.cleanBlock(aBlocks[ii].iAddress);
                                }
                            }

                            insertValue(pa_aKey, pa_iRowid);
                        }
                        else
                        {
                            //Treba reorganizovat pole
                            reorganizeArray(iDepth + 1);
                            insertValue(pa_aKey, pa_iRowid);
                        }
                    }
                }

                else
                {
                    if (piUsedBits == 32)
                    {
                        //Neda sa viac rozdelit pole, treba vytvorit preplnovaci bucket
                        long iPosition = getAddress(iArrayPosition);
                        oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iPosition, poFile.readBlock(iPosition), psKeyObjName, piKeyObjLength);
                        long iChain = oTempBlock.iChain;
                        while (iChain != -1)
                        {
                            oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iChain, poFile.readBlock(iChain), psKeyObjName, piKeyObjLength);
                            iChain = oTempBlock.iChain;
                        }
                        if (oTempBlock.iNumberOfRecords < piNumberOfRecordsInBucket)
                        {
                            oTempBlock.addRecord(pa_aKey, pa_iRowid);
                            poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                            if (pbUseImmediateStats == true)
                            {
                                if (oTempBlock.iAddress == iPosition)
                                {
                                    piRecordsInMainBlocks++;
                                }
                                else
                                {
                                    piRecordsInOverloadBlocks++;
                                }
                            }
                        }
                        else
                        {
                            // Prida sa novy preplnovaci blok
                            long iNewAddress = poFile.createNewBlock();
                            oTempBlock.iChain = iNewAddress;
                            poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());

                            oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iNewAddress, poFile.readBlock(iNewAddress), psKeyObjName, piKeyObjLength);
                            oTempBlock.addRecord(pa_aKey, pa_iRowid);
                            poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                            if (pbUseImmediateStats == true)
                            {
                                piRecordsInOverloadBlocks++;
                                piOverloadBlocks++;
                            }
                        }
                    }
                }
            }
            else
            {
                // Da sa normalne vlozit do bloku
                ArrayList oValues = new ArrayList();
                oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iArrayPosition), poFile.readBlock(getAddress(iArrayPosition)), psKeyObjName, piKeyObjLength);
                oTempBlock.addRecord(pa_aKey, pa_iRowid);
                poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                if (pbUseImmediateStats == true)
                {
                    piRecordsInMainBlocks++;
                }
            }
        }


       /// <summary>
       /// Updatuje blok s hodnotou a rowid
       /// </summary>
       /// <param name="pa_aKey">Kluc</param>
       /// <param name="pa_aNewKey">Novy kluc</param>
       /// <param name="pa_iRowid">Rowid</param>
       /// <param name="pa_iNewRowid">Nove rowid</param>
       /// <returns></returns>
        public bool updateValue(byte[] pa_aKey, byte[] pa_aNewKey, long pa_iRowid, long pa_iNewRowid)
        {
            // Ak sa nerovnaju kluce, tak treba stary odstranit a vlozit novy
            if (compareByte(pa_aKey, pa_aNewKey) == false)
            {
                deleteValue(pa_aKey, pa_iRowid);
                insertValue(pa_aNewKey, pa_iRowid);
                return true;
            }
            else
            {
                // Nacita sa blok, kde je kluc s rowid a zmeni sa 
                uint hash = getHash(pa_aKey);
                string binar = convertToBinary(hash);
                int iArrayPosition = convertFromBinary(binar.Substring(0, piUsedBits));
                int iFound;
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iArrayPosition), poFile.readBlock(getAddress(iArrayPosition)), psKeyObjName, piKeyObjLength);
                iFound = oTempBlock.containsKey(pa_aKey, pa_iRowid);
                while (iFound == -1 && oTempBlock.iChain != -1)
                {
                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                    iFound = oTempBlock.containsKey(pa_aKey, pa_iRowid);
                }
                if (iFound == -1)
                {
                    return false;
                }
                else
                {
                    oTempBlock[iFound].iRowid = pa_iNewRowid;
                    poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                    return true;
                }
            }
        }



        /// <summary>
        /// Vymaze zaznam s danym klucom a rowid
        /// </summary>
        /// <param name="pa_aKey"></param>
        /// <param name="pa_iRowid"></param>
        public bool deleteValue(byte[] pa_aKey, long pa_iRowid)
        {
            uint hash = getHash(pa_aKey);
            string binar = convertToBinary(hash);
            int iArrayPosition = convertFromBinary(binar.Substring(0, piUsedBits));
            int iFound;
            // Zoznam vsetkych blokov, ak su zretazene, kvoli mazaniu a posuvaniu zaznamov
            List<cIndBlock> aBlocks = new List<cIndBlock>();
            cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iArrayPosition), poFile.readBlock(getAddress(iArrayPosition)), psKeyObjName, piKeyObjLength);
            aBlocks.Add(oTempBlock);
            iFound = oTempBlock.containsKey(pa_aKey, pa_iRowid);
            while (iFound == -1 && oTempBlock.iChain != -1)
            {
                oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                iFound = oTempBlock.containsKey(pa_aKey, pa_iRowid);
                aBlocks.Add(oTempBlock);
            }
            if (iFound == -1)
            {
                return false;
            }
            else
            {
                // Neostanu ziadne zaznamy v bloku
                if (oTempBlock.iNumberOfRecords > 1)
                {
                    oTempBlock[iFound] = oTempBlock[oTempBlock.iNumberOfRecords - 1];
                    oTempBlock.deleteRecord(oTempBlock.iNumberOfRecords - 1);
                    oTempBlock.iNumberOfRecords--;
                    if (oTempBlock.iChain != -1)
                    {
                        int iOrderNo = aBlocks.Count - 1;
                        oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                        aBlocks.Add(oTempBlock);
                        while (oTempBlock.iChain != -1)
                        {
                            oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                            aBlocks.Add(oTempBlock);
                        }
                        aBlocks[iOrderNo].addRecord(oTempBlock[oTempBlock.iNumberOfRecords - 1].aKey, oTempBlock[oTempBlock.iNumberOfRecords - 1].iRowid);
                        oTempBlock.deleteRecord(oTempBlock.iNumberOfRecords - 1);
                        oTempBlock.iNumberOfRecords--;
                        if (oTempBlock.iNumberOfRecords == 0)
                        {
                            aBlocks[aBlocks.Count - 2].iChain = -1;
                            poFile.cleanBlock(oTempBlock.iAddress);
                            poFile.writeBlock(aBlocks[aBlocks.Count - 2].iAddress, aBlocks[aBlocks.Count - 2].toByteArray());
                            if (iOrderNo != aBlocks.Count - 2)
                            {
                                poFile.writeBlock(aBlocks[iOrderNo].iAddress, aBlocks[iOrderNo].toByteArray());
                            }
                        }
                        else
                        {
                            poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                            poFile.writeBlock(aBlocks[iOrderNo].iAddress, aBlocks[iOrderNo].toByteArray());
                        }
                    }
                    else
                    {
                        // Ostanu nejake zaznamy
                        poFile.writeBlock(oTempBlock.iAddress, oTempBlock.toByteArray());
                    }
                    if (pbUseImmediateStats == true)
                    {
                        if (aBlocks.Count > 1)
                        {
                            piRecordsInOverloadBlocks--;
                            piOverloadBlocks--;
                        }
                        else
                        {
                            piMainBlocks--;
                            piRecordsInMainBlocks--;
                        }
                    }
                }
                else
                {
                    poFile.cleanBlock(oTempBlock.iAddress);
                    if (aBlocks.Count > 1)
                    {
                        aBlocks[aBlocks.Count - 2].iChain = -1;
                        poFile.writeBlock(aBlocks[aBlocks.Count - 2].iAddress, aBlocks[aBlocks.Count - 2].toByteArray());
                    }
                    if (pbUseImmediateStats == true)
                    {
                        if (aBlocks.Count > 1)
                        {
                            piRecordsInOverloadBlocks--;
                            piOverloadBlocks--;
                        }
                        else
                        {
                            piMainBlocks--;
                            piRecordsInMainBlocks--;
                        }
                    }

                }
                piNumberOfDeleted++;
                // Ak pomer vymazanych a poctu zaznamov v bloku dosiahol kriticku hodnotu, tak sa optimalizuje pole
                if (Convert.ToInt32(piNumberOfDeleted / piNumberOfRecordsInBucket) >= piDeleteReorganizeRatio)
                {
                    optimizeArray();
                }
                return true;
            }
        }

        /// <summary>
        /// Najde kluc
        /// </summary>
        /// <param name="pa_aKey"></param>
        /// <returns></returns>
        public long findKey(byte[] pa_aKey)
        {
            uint hash = getHash(pa_aKey);
            string binar = convertToBinary(hash);
            int iArrayPosition = convertFromBinary(binar.Substring(0, piUsedBits));
            int iFound;
            cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iArrayPosition), poFile.readBlock(getAddress(iArrayPosition)), psKeyObjName, piKeyObjLength);
            iFound = oTempBlock.containsKey(pa_aKey, 1);
            while (iFound == -1 && oTempBlock.iChain != -1)
            {
                oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                iFound = oTempBlock.containsKey(pa_aKey, 1);
            }
            if (iFound == -1)
            {
                return -1;
            }
            else
            {
                paLastKey = pa_aKey;
                piFoundCount = 1;
                piLastAddressForSearch = oTempBlock.iAddress;
                return oTempBlock[iFound].iRowid;
            }
        }

        /// <summary>
        /// Najde dalsi kluc
        /// </summary>
        /// <param name="pa_aKey"></param>
        /// <returns></returns>
        public long findNextKey(byte[] pa_aKey)
        {
            // tu sa porovnava, ci je hodnota rovnaka, ako posledna vyhladavana, ak nie, tak sa hlada od zaciatku, inak dalsi
            if (compareByte(pa_aKey, paLastKey) == true)
            {
                int iFound;
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, piLastAddressForSearch, poFile.readBlock(piLastAddressForSearch), psKeyObjName, piKeyObjLength);
                iFound = oTempBlock.containsKey(pa_aKey, piFoundCount + 1);
                while (iFound == -1 && oTempBlock.iChain != -1)
                {
                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                    piFoundCount = 0;
                    iFound = oTempBlock.containsKey(pa_aKey, piFoundCount + 1);
                }
                if (iFound == -1)
                {
                    return -1;
                }
                else
                {
                    piFoundCount++;
                    piLastAddressForSearch = oTempBlock.iAddress;
                    return (oTempBlock[iFound]).iRowid;
                }
            }
            else
            {
                uint hash = getHash(pa_aKey);
                string binar = convertToBinary(hash);
                int iArrayPosition = convertFromBinary(binar.Substring(0, piUsedBits));
                int iFound;
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iArrayPosition), poFile.readBlock(getAddress(iArrayPosition)), psKeyObjName, piKeyObjLength);
                iFound = oTempBlock.containsKey(pa_aKey, 1);
                while (iFound == -1 && oTempBlock.iChain != -1)
                {
                    oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, oTempBlock.iChain, poFile.readBlock(oTempBlock.iChain), psKeyObjName, piKeyObjLength);
                    iFound = oTempBlock.containsKey(pa_aKey, 1);
                }
                if (iFound == -1)
                {
                    return -1;
                }
                else
                {
                    paLastKey = pa_aKey;
                    piFoundCount = 1;
                    piLastAddressForSearch = oTempBlock.iAddress;
                    return oTempBlock[iFound].iRowid;
                }
            }
        }



        #region hashovacie funkcie
        /// <summary>
        /// Vrati hash hodnotu pre kluce
        /// </summary>
        /// <param name="pa_oKeys"></param>
        /// <returns></returns>
        public uint getHash(byte[] pa_oKeys)
        {
            switch (piUsedHash)
            {
                case 0:
                    return fnvHash(pa_oKeys);
                case 1:
                    return bernstainHash(pa_oKeys);
                case 2:
                    return modifiedBernstainHash(pa_oKeys);
            }
            return 0;
        }

        private uint bernstainHash(byte[] pa_oKey)
        {
            byte[] oHlp = new byte[pa_oKey.Length];
            pa_oKey.CopyTo(oHlp, 0);
            uint h = 0;

            for (int i = 0; i < pa_oKey.Length; i++)
            {
                h = 33 * h + oHlp[i];
            }

            return h;
        }

        private uint modifiedBernstainHash(byte[] pa_oKey)
        {
            byte[] oHlp = new byte[pa_oKey.Length];
            pa_oKey.CopyTo(oHlp, 0);
            uint h = 0;

            for (int i = 0; i < pa_oKey.Length; i++)
            {
                h ^= (h << 5) + (h >> 2) + oHlp[i];
            }

            return h;
        }

        private uint fnvHash(byte[] pa_oKey)
        {
            byte[] oHlp = new byte[pa_oKey.Length];
            pa_oKey.CopyTo(oHlp, 0);
            uint h = 2166136261;

            for (int i = 0; i < pa_oKey.Length; i++)
            {

                h = (h * 16777619) ^ oHlp[i];

            }

            return h;
        }

        private uint myHash(byte[] pa_oKey)
        {
            uint iReturn = 0;
            for (int ii = 0; ii < pa_oKey.Length; ii++)
            {
                if (ii % 2 == 0)
                {
                    iReturn += (uint)pa_oKey[ii] * 7;
                }
                else
                {
                    iReturn += (uint)pa_oKey[ii] * 5;
                }
                iReturn = iReturn >> 2;
            }
            return iReturn;
        }
        
        #endregion

        #region pomocne funkcie
        private string Reverse(string pa_sString)
        {
            string sReturn = "";

            for (int i = pa_sString.Length - 1; i > -1; i--)
            {
                sReturn += pa_sString[i];
            }
            return sReturn;

        }
        /// <summary>
        /// Konverzia do binarnej hodnoty
        /// </summary>
        /// <param name="pa_iNumber"></param>
        /// <returns></returns>
        private string convertToBinary(uint pa_iNumber)
        {
            string sReturn = "";
            for (; pa_iNumber > 0; pa_iNumber /= 2)
            {
                sReturn = Convert.ToString(pa_iNumber % 2) + sReturn;
            }
            sReturn = sReturn.PadRight(32, '0');
            //return sReturn;
            return Reverse(sReturn);

        }

        /// <summary>
        /// Konverzia z binarnej podoby
        /// </summary>
        /// <param name="pa_sNumber"></param>
        /// <returns></returns>
        private int convertFromBinary(string pa_sNumber)
        {
            int iReturn = 0;
            int iCount = 0;
            for (int i = pa_sNumber.Length - 1; i >= 0; i--)
            {
                if (pa_sNumber[i] != '0')
                {
                    iReturn += (int)Math.Pow(2, iCount);
                }
                iCount++;
            }
            return iReturn;
        }



        private string convertToBinaryNo(int pa_iNumber)
        {
            string sReturn = "";
            if (pa_iNumber < 0)
            {
                pa_iNumber *= -1;
            }
            for (; pa_iNumber > 0; pa_iNumber /= 2)
            {
                sReturn = Convert.ToString(pa_iNumber % 2) + sReturn;
            }
            //sReturn = sReturn.PadLeft(32, '0');
            //return sReturn;
            return sReturn;
        } 
        #endregion

        /// <summary>
        /// Uprava pola smernikov pri vymazani dostatocneho poctu zaznamov
        /// </summary>
        private void optimizeArray()
        {
            bool wasChange = true;
            piNumberOfDeleted = 0;
            while (wasChange == true)
            {
                wasChange = false;
                int iPostion = 0;
                cIndBlock oFirstBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iPostion), poFile.readBlock(getAddress(iPostion)), psKeyObjName, piKeyObjLength);
                int iStartDepth = oFirstBlock.iDepth;
                bool bSame = true;
                while (iPostion <= piArrayCount - 1)
                {
                    oFirstBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iPostion), poFile.readBlock(getAddress(iPostion)), psKeyObjName, piKeyObjLength);
                    int iActDepth = oFirstBlock.iDepth;
                    if (iActDepth != iStartDepth)
                    {
                        bSame = false;
                    }
                    int iJump = (int)Math.Pow(2, piUsedBits - iActDepth);
                    if (iActDepth != 1)
                    {
                        int iActRecNo = oFirstBlock.iNumberOfRecords;
                        // je este kde posuvat
                        if (iPostion + iJump <= piArrayCount - 1)
                        {
                            cIndBlock oSecondBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, getAddress(iPostion + iJump), poFile.readBlock(getAddress(iPostion + iJump)), psKeyObjName, piKeyObjLength);
                            // hlbky sa rovnaju
                            if (iActDepth == oSecondBlock.iDepth)
                            {
                                string sBin = convertToBinaryNo(iPostion);
                                sBin = sBin.PadLeft(piUsedBits, '0');
                                string sJumpBin = convertToBinaryNo(iPostion + iJump);
                                sJumpBin = sJumpBin.PadLeft(piUsedBits, '0');
                                // je rovnaky aj d-ty bit sprava
                                if (sJumpBin.Substring(0, iActDepth - 1) == sBin.Substring(0, iActDepth - 1))
                                {
                                    // zmestia sa do jedneho
                                    if (iActRecNo + oSecondBlock.iNumberOfRecords <= piNumberOfRecordsInBucket)
                                    {
                                        for (int ii = 0; ii < oSecondBlock.iNumberOfRecords; ii++)
                                        {
                                            oFirstBlock.addRecord(oSecondBlock[ii].aKey, oSecondBlock[ii].iRowid);
                                        }
                                        oFirstBlock.iDepth--;
                                        poFile.writeBlock(oFirstBlock.iAddress, oFirstBlock.toByteArray());
                                        poFile.cleanBlock(oSecondBlock.iAddress);
                                        setArray(iPostion + iJump, iJump, getAddress(iPostion));
                                        iJump *= 2;
                                        wasChange = true;
                                        piMainBlocks--;
                                    }
                                }
                            }
                        }
                    }
                    iPostion = iPostion + iJump;
                }
                // vsetky su na rovnakej urovni
                if (bSame == true && piArrayCount != 2 && iStartDepth < piUsedBits)
                {
                    reorganizeArray(piUsedBits - 1);
                }
            }
        }

        /// <summary>
        /// Prikaz analyze
        /// </summary>
        /// <param name="pa_iMainBlocks">Pomer vyuzitia hl. blokov</param>
        /// <param name="pa_iOverloadBlocks">Pomer vyuzitia prepl. blokov</param>
        /// <param name="pa_oMax">Max</param>
        /// <param name="pa_oMin">Min</param>
        /// <param name="pa_iDiffVals">Pocet roznych hodnot</param>
        /// <param name="pa_iHistogramCols">Pocet stlpcov histogramu</param>
        /// <param name="aHistogram">Histogram</param>
        /// <param name="pa_bFillMinVals">Ci sa maju naplnit hodnotami udaje pre okamzite statistiky - pouziva sa pri prechode z analyze na okamzite stat.</param>
        public void analyze(out float pa_iMainBlocks, out float pa_iOverloadBlocks, out modul1.Object pa_oMax, out modul1.Object pa_oMin, out int pa_iDiffVals, int pa_iHistogramCols, out List<cHistogramColumn> aHistogram, bool pa_bFillMinVals)
        {
            pa_iMainBlocks = 0;
            pa_iOverloadBlocks = 0;
            int iMainBlocks = 0;
            int iOverloadBlocks = 0;
            long iMainVals = 0;
            long iOverloadVals = 0;
            pa_iDiffVals = 0;
            pa_oMin = null;
            pa_oMax = null;


            List<long> aOverloadBlocks = new List<long>();
            for (int ii = 0; ii < poFile.iNumberOfBlocks; ii++)
            {
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH), poFile.readBlock(ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH)), psKeyObjName, piKeyObjLength, true);
                if (oTempBlock.iChain != -1)
                {
                    aOverloadBlocks.Add(oTempBlock.iChain);
                }
                // Vyhladanie najmensieho a najvacsieho kluca
                if (pa_oMax == null && oTempBlock.iNumberOfRecords > 0)
                {
                    pa_oMax = oTempBlock[0].oValue;
                    pa_oMin = oTempBlock[0].oValue;
                }
                for (int ij = 0; ij < oTempBlock.iNumberOfRecords; ij++)
                {
                    if (oTempBlock[ij].oValue.Compare(pa_oMax) > 0)
                    {
                        pa_oMax = oTempBlock[ij].oValue;
                    }
                    if (oTempBlock[ij].oValue.Compare(pa_oMin) < 0)
                    {
                        pa_oMin = oTempBlock[ij].oValue;
                    }
                    if (pa_bFillMinVals == true)
                    {
                        addValue(oTempBlock[ij].oValue);
                    }
                }
                
            }
            // Vytvorenie histogramu
            aHistogram = new List<cHistogramColumn>();
            for (int ii = 0; ii < pa_iHistogramCols; ii++)
            {
                aHistogram.Add(new cHistogramColumn());
            }
            if (psKeyObjName == "hlavny.modul1.Boolean")
            {
                // Ak mame bool, tak potrebujem vzdy len 2 stlpce
                aHistogram[0].oMax = false;
                aHistogram[0].oMin = false;
                aHistogram[1].oMax = true;
                aHistogram[1].oMin = true;
                if (aHistogram.Count > 2)
                {
                    aHistogram.RemoveRange(2, aHistogram.Count - 2);
                }
            }
            else
            {
                if (psKeyObjName == "hlavny.modul1.Character")
                {
                    string sMin, sMax;
                    sMin = pa_oMin.ToString();
                    sMax = pa_oMax.ToString();
                    aHistogram[0].oMin = sMin;
                    aHistogram[pa_iHistogramCols - 1].oMax = sMax;
                    int iDiff = -1;
                    if (sMin.Length != sMax.Length)
                    {
                        if (sMax.Length > sMin.Length)
                        {
                            sMin.PadRight(sMax.Length, Convert.ToChar(255));
                        }
                        else
                        {
                            sMax.PadRight(sMin.Length, Convert.ToChar(1));
                        }
                    }
                    // Najde sa znak na ktorom sa min a max hodnota lisia
                    for (int ii = 0; ii < sMax.Length && ii < sMin.Length && iDiff == -1; ii++)
                    {
                        if (sMin[ii] != sMax[ii])
                        {
                            iDiff = ii;
                        }
                    }
                    // Min a max hodnota su rovnake
                    if (iDiff == -1)
                    {
                        aHistogram.RemoveRange(1, aHistogram.Count - 1);
                        aHistogram[0].oMax = sMax;
                    }
                    else
                    {
                        // Rozdiel medzi min a max na danom znaku sa rozdeli podla poctu stlpcov
                        float iSpace = (Convert.ToInt32(sMax[iDiff]) - Convert.ToInt32(sMin[iDiff])) / (pa_iHistogramCols);
                        string sBegin = sMax.Substring(0, iDiff);
                        int iBegin = Convert.ToInt32(sMin[iDiff]);
                        for (int ii = 0; ii < pa_iHistogramCols - 1; ii++)
                        {
                            if (ii == 0)
                            {
                                aHistogram[0].oMax = sBegin + Convert.ToChar(Convert.ToInt32(Math.Round((iBegin + iSpace), MidpointRounding.AwayFromZero)));
                            }
                            else
                            {
                                aHistogram[ii].oMin = (string)aHistogram[ii - 1].oMax;

                                aHistogram[ii].oMax = sBegin + Convert.ToChar(Convert.ToInt32(Math.Round((iBegin + iSpace * (ii + 1)), MidpointRounding.AwayFromZero)));
                            }
                        }
                        aHistogram[pa_iHistogramCols - 1].oMin = (string)aHistogram[pa_iHistogramCols - 2].oMax;

                        // Min a max hodnota stlpca sa nesmu rovnat, najde sa ci nieco take existuje, ak ano, tak sa najde 
                        // sekvencia hodnot, kde sa to vyskytuje a odstrani sa to
                        bool bChange = true;
                        while (bChange == true)
                        {
                            bChange = false;
                            int iLength;
                            for (int ii = 0; ii < aHistogram.Count; ii++)
                            {
                                // Maximalna a minimalna hodnota sa rovnaju
                                if (((string)aHistogram[ii].oMin).CompareTo(aHistogram[ii].oMax) == 0)
                                {
                                    iLength = 1;
                                    for (int ij = ii + 1; ij < aHistogram.Count; ij++)
                                    {
                                        if (((string)aHistogram[ij].oMax).CompareTo((string)aHistogram[ij].oMin) == 0 && ((string)aHistogram[ij].oMin).CompareTo((string)aHistogram[ii].oMin) == 0)
                                        {
                                            iLength++;
                                        }
                                    }
                                    iSpace = (254) / iLength;
                                    iBegin = Convert.ToInt32(sMin[iDiff]);
                                    aHistogram[ii].oMin = (string)aHistogram[ii].oMin + Convert.ToChar(1);
                                    for (int ik = ii; ik < ii + iLength; ik++)
                                    {
                                        Console.WriteLine((ik - ii) * iSpace +1);
                                        aHistogram[ik].oMax = (string)aHistogram[ik].oMin + Convert.ToChar(Convert.ToInt32(Math.Round((ik - ii) * iSpace +1, MidpointRounding.AwayFromZero)));
                                        if (aHistogram.Count > ik + 1)
                                        {
                                            aHistogram[ik + 1].oMin = aHistogram[ik].oMax;
                                        }
                                    }
                                    aHistogram[ii + iLength].oMin = (string)aHistogram[ii + iLength-1].oMax;
                                    if (ii > 0)
                                    {
                                        aHistogram[ii - 1].oMax = aHistogram[ii].oMin;

                                    }
                                    bChange = true;
                                    // Aby som neprechadzal uz prerobene veci
                                    ii += iLength;
                                }
                            }
                        }
                        // Hodnoty sa kvoli porovnavaniam doplnia na potrebnu dlzku
                        for (int ii = 0; ii < aHistogram.Count; ii++)
                        {
                            if (ii > 0)
                            {
                                aHistogram[ii].oMin = ((string)aHistogram[ii].oMin).PadRight(piKeyObjLength, Convert.ToChar(255));
                            }
                            if (ii < aHistogram.Count -1)
                            {
                                aHistogram[ii].oMax = ((string)aHistogram[ii].oMax).PadRight(piKeyObjLength, Convert.ToChar(255));
                            }
                        }
                    }
                }
                else
                {
                    // Klasicky numericky histogram
                    aHistogram[0].oMin = Convert.ToDouble(pa_oMin.ToString());
                    aHistogram[pa_iHistogramCols - 1].oMax = Convert.ToDouble(pa_oMax.ToString());
                    double iSpace = ((double)aHistogram[pa_iHistogramCols - 1].oMax - (double)aHistogram[0].oMin) / pa_iHistogramCols;
                    for (int ii = 0; ii < pa_iHistogramCols - 1; ii++)
                    {
                        if (ii == 0)
                        {
                            aHistogram[0].oMax = (double)aHistogram[0].oMin + iSpace;
                        }
                        else
                        {
                            aHistogram[ii].oMin = (double)aHistogram[ii - 1].oMax;

                            aHistogram[ii].oMax = (double)aHistogram[ii].oMin + iSpace;
                        }
                    }
                    aHistogram[pa_iHistogramCols - 1].oMin = (double)aHistogram[pa_iHistogramCols - 2].oMax;
                }
            }
            for (int i = 0; i < poFile.iNumberOfBlocks; i++)
            {
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, i * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH), poFile.readBlock(i * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH)), psKeyObjName, piKeyObjLength, true);
                if (aOverloadBlocks.Contains(oTempBlock.iAddress) == true)
                {
                    iOverloadBlocks++;
                    iOverloadVals += oTempBlock.iNumberOfRecords;
                }
                else
                {
                    if (oTempBlock.bUsed == true)
                    {
                        iMainBlocks++;
                        iMainVals += oTempBlock.iNumberOfRecords;

                        // Nacitaju sa aj zretazene bloky
                        List<cIndBlock> aBlocks = new List<cIndBlock>();
                        List<modul1.Object> aValues = new List<hlavny.modul1.Object>();
                        aBlocks.Add(oTempBlock);
                        long iChain = oTempBlock.iChain;
                        while (iChain != -1)
                        {
                            aBlocks.Add(new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, iChain, poFile.readBlock(iChain), psKeyObjName, piKeyObjLength, true));
                            iChain = aBlocks[aBlocks.Count - 1].iChain;
                        }
                        
                        
                        for (int ii = 0; ii < aBlocks.Count; ii++)
                        {
                            for (int ij = 0; ij < aBlocks[ii].iNumberOfRecords; ij++)
                            {
                                // Pocet roznych hodnot
                                if (aValues.Contains(aBlocks[ii][ij].oValue) == false)
                                {
                                    pa_iDiffVals++;
                                    aValues.Add(aBlocks[ii][ij].oValue);
                                }

                                // Histogram
                                if (pa_oMin != null && pa_oMax != null)
                                {
                                    if (psKeyObjName == "hlavny.modul1.Boolean")
                                    {
                                        if (string.Compare(oTempBlock[ij].oValue.ToString(), "True") == 0)
                                        {
                                            aHistogram[1].iValues++;
                                        }
                                        else
                                        {
                                            aHistogram[0].iValues++;
                                        }
                                    }
                                    else
                                    {
                                        if (psKeyObjName == "hlavny.modul1.Character")
                                        {
                                            string sVal = aBlocks[ii][ij].oValue.ToString();
                                            for (int ik = 0; ik < aHistogram.Count; ik++)
                                            {
                                                if (stringComparator((string)aHistogram[ik].oMin, sVal) >= 0 && stringComparator((string)aHistogram[ik].oMax, sVal) < 0)
                                                {
                                                    aHistogram[ik].iValues++;
                                                    break;
                                                }
                                            }
                                            if (aBlocks[ii][ij].oValue.ToString() == pa_oMax.ToString())
                                            {
                                                aHistogram[aHistogram.Count - 1].iValues++;
                                            }
                                        }
                                        else
                                        {
                                            double iVal = Convert.ToDouble(aBlocks[ii][ij].oValue.ToString());
                                            for (int ik = 0; ik < aHistogram.Count; ik++)
                                            {
                                                if ((double)aHistogram[ik].oMin <= iVal && (double)aHistogram[ik].oMax > iVal)
                                                {
                                                    aHistogram[ik].iValues++;
                                                    break;
                                                }
                                            }
                                            if (aBlocks[ii][ij].oValue.ToString().CompareTo(pa_oMax.ToString()) == 0)
                                            {
                                                aHistogram[aHistogram.Count - 1].iValues++;
                                            }
                                        }
                                    } 
                                }
                            }
                        }
                    }
                }
            }

            if (iMainVals != 0)
            {
                pa_iMainBlocks = ((float)iMainVals / ((float)iMainBlocks * (float)piNumberOfRecordsInBucket));
            }
            else
            {
                pa_iMainBlocks = 0;
            }

            if (iOverloadVals != 0)
            {
                pa_iOverloadBlocks = (float)iOverloadVals / ((float)iOverloadBlocks * (float)piNumberOfRecordsInBucket);
            }
            else
            {
                pa_iOverloadBlocks = 0;
            }
            // Ak treba tak sa naplnia potrebne udaje v subore
            if (pa_bFillMinVals == true)
            {
                piMainBlocks = iMainBlocks;
                piOverloadBlocks = iOverloadBlocks;
                piRecordsInMainBlocks = iMainVals;
                piRecordsInOverloadBlocks = iOverloadVals;
                piDifValues = pa_iDiffVals;
            }
        }


        /// <summary>
        /// Porovna 2 stringy podla ASCII hodnoty
        /// </summary>
        /// <param name="pa_sVal1"></param>
        /// <param name="pa_sVal2"></param>
        /// <returns>0 ak sa rovnaju, -1 ak je prve vacsie, 1 ak je 2. vacsie</returns>
        private int stringComparator(string pa_sVal1, string pa_sVal2)
        {
            for (int ii = 0; ii < pa_sVal1.Length && ii < pa_sVal2.Length; ii++)
            {
                int iA = Convert.ToInt32(pa_sVal1[ii]), iB = Convert.ToInt32(pa_sVal2[ii]);
                if (iA > iB)
                {
                    return -1;
                }
                else
                {
                    if (iA < iB)
                    {
                        return 1;
                    }
                }
            }
            if (pa_sVal2.Length == pa_sVal1.Length)
            {
                return 0;
            }
            else
            {
                if (pa_sVal2.Length > pa_sVal1.Length)
                {
                    return 1;
                }
                else
                {
                    return -1;
                }
            }


        }


        /// <summary>
        /// Pri vkladani noveho prvku treba overit, ci nepatri medzi najvacsie alebo najmensie
        /// </summary>
        /// <param name="pa_oValue"></param>
        public void addValue(hlavny.modul1.Object pa_oValue)
        {
            if (pbFilled == false)
            {
                // Este neni plne, treba doplnit
                paMaxValues.Add(pa_oValue);
                sortList(ref paMaxValues, false);
                paMinValues.Add(pa_oValue);
                sortList(ref paMinValues, true);
                if (paMinValues.Count == 10 && paMaxValues.Count == 10)
                {
                    pbFilled = true;
                }
                poMaxValue = paMaxValues[0];
                poMinValue = paMinValues[0];
            }
            else
            {
                // Ci sa vobec ma vkladat
                bool canChange = false;
                for (int ii = 0; ii < paMaxValues.Count; ii++)
                {
                    if (pa_oValue.Compare(paMaxValues[ii]) >= 0)
                    {
                        canChange = true;
                    }
                }
                // Ak ano, tak sa upravi pole
                if (canChange == true)
                {
                    paMaxValues.Add(pa_oValue);
                    sortList(ref paMaxValues, false);
                    paMaxValues.RemoveAt(paMaxValues.Count - 1);
                    poMaxValue = paMaxValues[0];
                }

                for (int ii = 0; ii < paMinValues.Count; ii++)
                {
                    if (pa_oValue.Compare(paMinValues[ii]) <= 0)
                    {
                        canChange = true;
                    }
                }
                if (canChange == true)
                {
                    paMinValues.Add(pa_oValue);
                    sortList(ref paMinValues, true);
                    paMinValues.RemoveAt(paMinValues.Count - 1);
                    poMinValue = paMinValues[0];
                }
                
            }
        }

        /// <summary>
        /// Odstrani hodnotu zo suboru s min a max hodnotami
        /// </summary>
        /// <param name="pa_oValue"></param>
        public void removeValue(hlavny.modul1.Object pa_oValue)
        {
            // Najde vyberanu hodnotu, ak existuje, tak ju odstrani, ak uz v poli min alebo max. hodnot neostane dost prvkov, tak sa naplni
            if (paMinValues.Contains(pa_oValue))
            {
                for (int ii = 0; ii < paMinValues.Count; ii++)
                {
                    if (paMinValues[ii].Compare(pa_oValue) == 0)
                    {
                        if (paMinValues.Count > 1)
                        {
                            paMinValues[ii] = paMinValues[paMinValues.Count - 1];
                            paMinValues.RemoveAt(paMinValues.Count - 1);
                            sortList(ref paMinValues, true);
                            poMinValue = paMinValues[0];
                        }
                        paMinValues.RemoveAt(paMinValues.Count-1);
                        if(paMinValues.Count == 0)
                        {
                            fillMinValues();
                        }
                        break;
                    }
                }
            }
            if (paMaxValues.Contains(pa_oValue))
            {
                for (int ii = 0; ii < paMaxValues.Count; ii++)
                {
                    if (paMaxValues[ii].Compare(pa_oValue) == 0)
                    {
                        if (paMaxValues.Count > 1)
                        {
                            paMaxValues[ii] = paMaxValues[paMaxValues.Count - 1];
                            paMaxValues.RemoveAt(paMaxValues.Count - 1);
                            sortList(ref paMaxValues, true);
                            poMaxValue = paMaxValues[0];
                        }
                        paMaxValues.RemoveAt(paMaxValues.Count-1);
                        if(paMaxValues.Count == 0)
                        {
                            fillMinValues();
                        }
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Prejde subor a naplni polia s minimalnymi a maximalnymi hodnotami
        /// </summary>
        public void fillMinValues()
        {
            paMaxValues.Clear();
            paMinValues.Clear();
            pbFilled = false;
            for (int ii = 0; ii < poFile.iNumberOfBlocks; ii++)
            {
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH), poFile.readBlock(ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH)), psKeyObjName, piKeyObjLength, true);
                for (int ij = 0; ij < oTempBlock.iNumberOfRecords; ij++)
                {
                    addValue(oTempBlock[ij].oValue);
                }
            }
        }

        /// <summary>
        /// Utriedi zoznam
        /// </summary>
        /// <param name="pa_oList"></param>
        /// <param name="pa_bAsc"></param>
        public void sortList(ref List<hlavny.modul1.Object> pa_oList, bool pa_bAsc)
        {
            if (pa_bAsc == true)
            {
                modul1.Object oHlp;
                for (int ii = 0; ii < pa_oList.Count-1; ii++)
                {
                    for (int ij = ii++; ij < pa_oList.Count; ij++)
                    {
                        if(pa_oList[ii].Compare(pa_oList[ij]) < 0)
                        {
                            oHlp = pa_oList[ij];
                            pa_oList[ij] = pa_oList[ii];
                            pa_oList[ii] = pa_oList[ij];
                        }
                    }   
                }
            }
            else
            {
                modul1.Object oHlp;
                for (int ii = 0; ii < pa_oList.Count-1; ii++)
                {
                    for (int ij = ii++; ij < pa_oList.Count; ij++)
                    {
                        if(pa_oList[ii].Compare(pa_oList[ij]) > 0)
                        {
                            oHlp = pa_oList[ij];
                            pa_oList[ij] = pa_oList[ii];
                            pa_oList[ii] = pa_oList[ij];
                        }
                    }   
                }
            }
        }
        
        /// <summary>
        /// Vrati histogram s danym poctom stlpcov, to iste ako pri analyze
        /// </summary>
        /// <param name="pa_oMin"></param>
        /// <param name="pa_oMax"></param>
        /// <returns></returns>
        public List<cHistogramColumn> getHistogram(hlavny.modul1.Object pa_oMin, hlavny.modul1.Object pa_oMax, int pa_iHistogramCols)
        {
            if (pa_oMax == null || pa_oMin == null)
            {
                return null;
            }
            List<cHistogramColumn> aHistogram = new List<cHistogramColumn>();
            for (int ii = 0; ii < pa_iHistogramCols; ii++)
            {
                aHistogram.Add(new cHistogramColumn());
            }
            if (psKeyObjName == "hlavny.modul1.Boolean")
            {
                aHistogram[0].oMax = false;
                aHistogram[0].oMin = false;
                aHistogram[1].oMax = true;
                aHistogram[1].oMin = true;
                if (aHistogram.Count > 2)
                {
                    aHistogram.RemoveRange(2, aHistogram.Count - 2);
                }
            }
            else
            {
                if (psKeyObjName == "hlavny.modul1.Character")
                {
                    string sMin, sMax;
                    sMin = pa_oMin.ToString();
                    sMax = pa_oMax.ToString();
                    aHistogram[0].oMin = sMin;
                    aHistogram[pa_iHistogramCols - 1].oMax = sMax;
                    int iDiff = -1;
                    if (sMin.Length != sMax.Length)
                    {
                        if (sMax.Length > sMin.Length)
                        {
                            sMin.PadRight(sMax.Length, Convert.ToChar(255));
                        }
                        else
                        {
                            sMax.PadRight(sMin.Length, Convert.ToChar(1));
                        }
                    }

                    for (int ii = 0; ii < sMax.Length && ii < sMin.Length && iDiff == -1; ii++)
                    {
                        if (sMin[ii] != sMax[ii])
                        {
                            iDiff = ii;
                        }
                    }
                    if (iDiff == -1)
                    {
                        aHistogram.RemoveRange(1, aHistogram.Count - 1);
                        aHistogram[0].oMax = sMax;
                    }
                    else
                    {
                        float iSpace = (Convert.ToInt32(sMax[iDiff]) - Convert.ToInt32(sMin[iDiff])) / (pa_iHistogramCols);
                        string sBegin = sMax.Substring(0, iDiff);
                        int iBegin = Convert.ToInt32(sMin[iDiff]);
                        for (int ii = 0; ii < pa_iHistogramCols - 1; ii++)
                        {
                            if (ii == 0)
                            {
                                aHistogram[0].oMax = sBegin + Convert.ToChar(Convert.ToInt32(Math.Round((iBegin + iSpace), MidpointRounding.AwayFromZero)));
                            }
                            else
                            {
                                aHistogram[ii].oMin = (string)aHistogram[ii - 1].oMax;

                                aHistogram[ii].oMax = sBegin + Convert.ToChar(Convert.ToInt32(Math.Round((iBegin + iSpace * (ii + 1)), MidpointRounding.AwayFromZero)));
                            }
                        }
                        aHistogram[pa_iHistogramCols - 1].oMin = (string)aHistogram[pa_iHistogramCols - 2].oMax;

                        bool bChange = true;
                        while (bChange == true)
                        {
                            bChange = false;
                            int iLength;
                            for (int ii = 0; ii < aHistogram.Count; ii++)
                            {
                                // Maximalna a minimalna hodnota sa rovnaju
                                if (((string)aHistogram[ii].oMin).CompareTo(aHistogram[ii].oMax) == 0)
                                {
                                    iLength = 1;
                                    for (int ij = ii + 1; ij < aHistogram.Count; ij++)
                                    {
                                        if (((string)aHistogram[ij].oMax).CompareTo((string)aHistogram[ij].oMin) == 0 && ((string)aHistogram[ij].oMin).CompareTo((string)aHistogram[ii].oMin) == 0)
                                        {
                                            iLength++;
                                        }
                                    }
                                    iSpace = (254) / iLength;
                                    iBegin = Convert.ToInt32(sMin[iDiff]);
                                    aHistogram[ii].oMin = (string)aHistogram[ii].oMin + Convert.ToChar(1);
                                    for (int ik = ii; ik < ii + iLength; ik++)
                                    {
                                        Console.WriteLine((ik - ii) * iSpace + 1);
                                        aHistogram[ik].oMax = (string)aHistogram[ik].oMin + Convert.ToChar(Convert.ToInt32(Math.Round((ik - ii) * iSpace + 1, MidpointRounding.AwayFromZero)));
                                        if (aHistogram.Count > ik + 1)
                                        {
                                            aHistogram[ik + 1].oMin = aHistogram[ik].oMax;
                                        }
                                    }
                                    aHistogram[ii + iLength].oMin = (string)aHistogram[ii + iLength - 1].oMax;
                                    if (ii > 0)
                                    {
                                        aHistogram[ii - 1].oMax = aHistogram[ii].oMin;

                                    }
                                    bChange = true;
                                    // Aby som neprechadzal uz prerobene veci
                                    ii += iLength;
                                }
                            }
                        }
                        for (int ii = 0; ii < aHistogram.Count; ii++)
                        {
                            if (ii > 0)
                            {
                                aHistogram[ii].oMin = ((string)aHistogram[ii].oMin).PadRight(piKeyObjLength, Convert.ToChar(255));
                            }
                            if (ii < aHistogram.Count - 1)
                            {
                                aHistogram[ii].oMax = ((string)aHistogram[ii].oMax).PadRight(piKeyObjLength, Convert.ToChar(255));
                            }
                        }
                    }
                }
                else
                {
                    aHistogram[0].oMin = Convert.ToDouble(pa_oMin.ToString());
                    aHistogram[pa_iHistogramCols - 1].oMax = Convert.ToDouble(pa_oMax.ToString());
                    double iSpace = ((double)aHistogram[pa_iHistogramCols - 1].oMax - (double)aHistogram[0].oMin) / pa_iHistogramCols;
                    for (int ii = 0; ii < pa_iHistogramCols - 1; ii++)
                    {
                        if (ii == 0)
                        {
                            aHistogram[0].oMax = (double)aHistogram[0].oMin + iSpace;
                        }
                        else
                        {
                            aHistogram[ii].oMin = (double)aHistogram[ii - 1].oMax;

                            aHistogram[ii].oMax = (double)aHistogram[ii].oMin + iSpace;
                        }
                    }
                    aHistogram[pa_iHistogramCols - 1].oMin = (double)aHistogram[pa_iHistogramCols - 2].oMax;
                }
            }
            for (int i = 0; i < poFile.iNumberOfBlocks; i++)
            {
                cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, i * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH), poFile.readBlock(i * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH)), psKeyObjName, piKeyObjLength, true);
                for (int ij = 0; ij < oTempBlock.iNumberOfRecords; ij++)
                {
                    if (psKeyObjName == "hlavny.modul1.Boolean")
                    {
                        if (string.Compare(oTempBlock[ij].oValue.ToString(), "True") == 0)
                        {
                            aHistogram[1].iValues++;
                        }
                        else
                        {
                            aHistogram[0].iValues++;
                        }
                    }
                    else
                    {
                        if (psKeyObjName == "hlavny.modul1.Character")
                        {
                            string sVal = oTempBlock[ij].oValue.ToString();
                            for (int ik = 0; ik < aHistogram.Count; ik++)
                            {
                                if (stringComparator((string)aHistogram[ik].oMin, sVal) >= 0 && stringComparator((string)aHistogram[ik].oMax, sVal) < 0)
                                {
                                    aHistogram[ik].iValues++;
                                    break;
                                }
                            }
                            if (oTempBlock[ij].oValue.ToString() == pa_oMax.ToString())
                            {
                                aHistogram[aHistogram.Count - 1].iValues++;
                            }
                        }
                        else
                        {
                            double iVal = Convert.ToDouble(oTempBlock[ij].oValue.ToString());
                            for (int ik = 0; ik < aHistogram.Count; ik++)
                            {
                                if ((double)aHistogram[ik].oMin <= iVal && (double)aHistogram[ik].oMax > iVal)
                                {
                                    aHistogram[ik].iValues++;
                                    break;
                                }
                            }
                            if (oTempBlock[ij].oValue.ToString().CompareTo(pa_oMax.ToString()) == 0)
                            {
                                aHistogram[aHistogram.Count - 1].iValues++;
                            }

                        }

                    }
                }
            }
            return aHistogram;
        }
        

        /// <summary>
        /// Vypise obsah suboru do textoveho suboru a na konzolu
        /// </summary>
        /// <param name="pa_sFilename"></param>
        public void toTextFile(string pa_sFilename)
        {
            FileStream rFile = null;
            try
            {
                rFile = File.Create(pa_sFilename);
                TextWriter rWriter = new StreamWriter(rFile);
                rFile.Seek(0, SeekOrigin.Begin);
                for (int ii = 0; ii < poFile.iNumberOfBlocks; ii++)
                {
                    cIndBlock oTempBlock = new cIndBlock(piKeyLength, piNumberOfRecordsInBucket, ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH), poFile.readBlock(ii * (piRecordLength * piNumberOfRecordsInBucket + HEADER_LENGTH)), psKeyObjName, piKeyObjLength, true);
                    rWriter.WriteLine("BLOK: " + oTempBlock.iAddress + " " + oTempBlock.bUsed.ToString() + " " + oTempBlock.iNumberOfRecords);
                    Console.WriteLine("BLOK: " + oTempBlock.iAddress + " " + oTempBlock.bUsed.ToString() + " " + oTempBlock.iNumberOfRecords);
                    for (int ij = 0; ij < oTempBlock.iNumberOfRecords; ij++)
                    {
                        Console.WriteLine(ij + " - " + oTempBlock[ij].oValue.ToString() + " : " + oTempBlock[ij].iRowid);
                        rWriter.WriteLine(ij + " - " + oTempBlock[ij].oValue.ToString() + " : " + oTempBlock[ij].iRowid);
                    }
                }
                rFile.Flush();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw ex;
            }
            finally
            {
                rFile.Flush();
                rFile.Close();
            }
        }
    }
}

